// Copyright 2012 Sergio, Raul, Dorival. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef GEMLAB_DEFS_H
#define GEMLAB_DEFS_H

namespace GemLab {

#ifndef VTU_NEWLINE_DEFINED
  #define VTU_NEWLINE_DEFINED
  #define VTU_NEWLINE(I,K,N,KMAX,OF) if (K>KMAX) { OF<<(I<N-1?"\n        ":"\n"); K=0; } else if (I==N-1) { OF<<"\n"; }
#endif

#define NOEDGE    {-1,-1,-1}
#define NOFACE    {-1,-1,-1,-1}
#define NOEDGES   {NOEDGE,NOEDGE,NOEDGE,NOEDGE}
#define NOEDGES3D {NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE}
#define NOFACES   {NOFACE,NOFACE,NOFACE,NOFACE,NOFACE,NOFACE}

size_t MaxNVerts2D               = 8;
size_t NVertsToNEdges2D[]        = {0,0,0,3,4,0,3,0,4};
size_t NVertsToNVertsPerEdge2D[] = {0,0,0,2,2,0,3,0,3};
int    NVertsToEdge2D[][4/*edges at most*/][3/*verts per edge at most*/]=
{
    NOEDGES,NOEDGES,NOEDGES,               // 0,1,2 verts
    {{0,1,-1},{1,2,-1},{2,0,-1},NOEDGE},   // 3 verts => TRIANGLE
    {{0,1,-1},{1,2,-1},{2,3,-1},{3,0,-1}}, // 4 verts => QUAD
    NOEDGES,                               // 5 verts
    {{0,1,3},{1,2,4},{2,0,5},NOEDGE},      // 6 verts => O2 TRIANGLE
    NOEDGES,                               // 7 verts
    {{0,1,4},{1,2,5},{2,3,6},{3,0,7}}      // 8 verts => O2 QUAD
};

size_t MaxNVerts3D               = 20;
size_t NVertsToNFaces3D[]        = {0,0,0,0, 4, 0,0,0, 6, 0, 4, 0,0,0,0,0,0,0,0,0, 6};
size_t NVertsToNVertsPerFace3D[] = {0,0,0,0, 3, 0,0,0, 4, 0, 3, 0,0,0,0,0,0,0,0,0, 4}; // disregarding O2 nodes
int    NVertsToFace3D[][6/*faces at most*/][4/*verts per face at most*/]=
{
    NOFACES,NOFACES,NOFACES,NOFACES,                                         //  0,1,2,3 verts
    {{0,3,2,-1},{0,1,3,-1},{0,2,1,-1},{1,2,3,-1},NOFACE,NOFACE},             //  4 verts => TETRA
    NOFACES,NOFACES,NOFACES,                                                 //  5,6,7 verts
    {{0,4,7,3},{1,2,6,5},{0,1,5,4},{2,3,7,6},{0,3,2,1},{4,5,6,7}},           //  8 verts => HEX
    NOFACES,                                                                 //  9 verts
    {{0,3,2,-1},{0,1,3,-1},{0,2,1,-1},{1,2,3,-1},NOFACE,NOFACE},             // 10 verts => O2 TETRA
    NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES, // 11,12,13,14,15,16,17,18,19 verts
    {{0,4,7,3},{1,2,6,5},{0,1,5,4},{2,3,7,6},{0,3,2,1},{4,5,6,7}}            // 20 verts => O2 HEX
};

size_t NVertsToNEdges3D[] = {0,0,0,0, 6, 0,0,0, 12, 0, 6, 0,0,0,0,0,0,0,0,0, 12};
int    NVertsToEdge3D[][12/*edges at most*/][3/*verts per edge at most*/]=
{
    NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,                                                                       //  0,1,2,3 verts
    {{0,1,-1},{1,2,-1},{2,0,-1},{0,3,-1},{1,3,-1},{2,3,-1},NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE},             //  4 verts => TETRA
    NOEDGES3D,NOEDGES3D,NOEDGES3D,                                                                                 //  5,6,7 verts
    {{0,1,-1},{1,2,-1},{2,3,-1},{3,0,-1},{4,5,-1},{5,6,-1},{6,7,-1},{7,4,-1},{0,4,-1},{1,5,-1},{2,6,-1},{3,7,-1}}, //  8 verts => HEX
    NOEDGES3D,                                                                                                     //  9 verts
    {{0,1,4},{1,2,5},{2,0,6},{0,3,7},{1,3,8},{2,3,9},NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE},                   // 10 verts => O2 TETRA
    NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,                     // 11,12,13,14,15,16,17,18,19 verts
    {{0,1,8},{1,2,9},{2,3,10},{3,0,11},{4,5,12},{5,6,13},{6,7,14},{7,4,15},{0,4,16},{1,5,17},{2,6,18},{3,7,19}}    // 20 verts => O2 HEX
};

#define NONE 0
size_t NVertsToGeoNVerts2D[] = {NONE,              // 0 verts
                                NONE,              // 1 vert
                                 2,                // 2 verts
                                 3,                // 3
                                 4,                // 4
                                NONE,              // 5
                                 3,                // 6
                                NONE,              // 7
                                 4,                // 8
                                NONE,NONE,NONE,    // 9,10,11
                                NONE,NONE,NONE,    // 12,13,14
                                 3};               // 15

size_t NVertsToGeoNVerts3D[] = {NONE,                       //  0 verts
                                NONE,                       //  1 vert
                                 2,                         //  2 verts
                                NONE,                       //  3
                                 4,                         //  4
                                NONE,                       //  5
                                NONE,                       //  6
                                NONE,                       //  7
                                 8,                         //  8
                                NONE,                       //  9
                                 4,                         // 10
                                NONE,NONE,NONE,NONE,NONE,   // 11,12,13,14,15
                                NONE,NONE,NONE,NONE,        // 16,17,18,19
                                 8};                        // 20
#undef NONE

#define BRYKEY(num_verts,idx_cell,idx_bry)                                      \
    int vert_a, vert_b, vert_c=-1, vert_d=-1;                                   \
    if (NDim==2)                                                                \
    {                                                                           \
        vert_a = Cells[idx_cell]->V[NVertsToEdge2D[num_verts][idx_bry][0]]->ID; \
        vert_b = Cells[idx_cell]->V[NVertsToEdge2D[num_verts][idx_bry][1]]->ID; \
        GemLab::Sort (vert_a,vert_b);                                           \
    }                                                                           \
    else                                                                        \
    {                                                                           \
        vert_a = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][0]]->ID; \
        vert_b = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][1]]->ID; \
        vert_c = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][2]]->ID; \
        if (NVertsToNVertsPerFace3D[num_verts]>3)                               \
        vert_d = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][3]]->ID; \
        GemLab::Sort (vert_a,vert_b,vert_c,vert_d);                             \
    }                                                                           \
    BryKey_t brykey(vert_a,vert_b,vert_c,vert_d);

#undef NOEDGE
#undef NOFACE
#undef NOEDGES
#undef NOFACES

}; // namespace GemLab

#endif // GEMLAB_DEFS_H
